﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace InCom.Core.TerminalSend.MappedFile
{
    /// <summary>
    /// 文件流同时读写
    /// 实际写入测试达到19万条记录每秒(第条40字节)
    /// 实际读取测试达到35万条记录每秒(第条40字节,默认每次读取2KB数据)
    /// 数据达到第条3KB时 写入2.4万每秒,读取2.2万每秒(内存稳定)
    /// </summary>
    public class FileStreamWriteRead : IDisposable
    {


        #region 属性
        /// <summary>
        /// 同时读写的文件名
        /// </summary>
        public string FileName { get; protected set; }

        /// <summary>
        /// 当前读的文件长度
        /// </summary>
        private long currentRead = 0;

        /// <summary>
        /// 当前读的当前长度
        /// </summary>
        public long CurrentRead
        {
            get
            {
                return System.Threading.Interlocked.Read(ref currentRead);
            }
            protected set
            {
                System.Threading.Interlocked.Exchange(ref currentRead, value);
            }

        }

        /// <summary>
        /// 当前写入数据长度
        /// </summary>
        private long cureentWrite = 0;
        /// <summary>
        /// 当前写入数据长度
        /// </summary>
        public long CureentWrite
        {
            get
            {
                return System.Threading.Interlocked.Read(ref cureentWrite);
            }
            protected set
            {
                System.Threading.Interlocked.Exchange(ref cureentWrite, value);
            }
        }

        /// <summary>
        /// 写入文件流
        /// </summary>
        private System.IO.BinaryWriter wrieStream;


        /// <summary>
        /// 读取文件流
        /// </summary>
        private System.IO.BinaryReader readStream;

        /// <summary>
        ///写入文件流
        /// </summary>
        protected BinaryWriter WrieStream
        {
            get { return wrieStream; }
        }

        /// <summary>
        /// 读取文件流
        /// </summary>
        protected BinaryReader ReadStream
        {
            get { return readStream; }
        }

        #endregion

        /// <summary>
        /// 写文件流
        /// </summary>
        protected FileStream writeFileStrema = null;
        /// <summary>
        /// 读文件流
        /// </summary>
        protected FileStream readFileStrema = null;


        /// <summary>
        /// 创建一个新的文件同时读写类
        /// </summary>
        /// <param name="fileName">文件名</param>
        public FileStreamWriteRead(string fileName)
        {
            FileName = fileName;
            //目录
            string dir = System.IO.Path.GetDirectoryName(FileName);
            //处理文件目录
            if (!System.IO.Directory.Exists( dir))
            {
                System.IO.Directory.CreateDirectory(dir);
            }
            //文件不存在则创建新文件
            if(!System.IO.File.Exists(FileName))
            {
                writeFileStrema = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
                readFileStrema = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
            }
            else
            {
                writeFileStrema = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
                readFileStrema = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
            }
            //创建写入流
            wrieStream = new BinaryWriter(writeFileStrema);
            //创建读取流
            readStream = new BinaryReader(readFileStrema);

            //可以读写
            CanWriteRead = true;

        }


        /// <summary>
        /// 最后数据保存时间
        /// </summary>
        public DateTime LastSaveTime { get; protected set; }

        /// <summary>
        /// 是否可读写
        /// </summary>
        public bool CanWriteRead
        {
            get { return canWriteRead; }
          protected  set { canWriteRead = value; }
        }

        #region 公共方法
        /// <summary>
        /// 写文件
        /// </summary>
        /// <param name="str"></param>
        public void Write(byte[] str)
        {
            if (!CanWriteRead)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            lock (wrieStream)
            {
                wrieStream.Write(str);
                wrieStream.Flush();
            }
            CureentWrite = wrieStream.BaseStream.Length;
            //设置最后时间
            LastSaveTime = DateTime.Now;
        }
        /// <summary>
        /// 默认定义数据
        /// </summary>
        private byte[] defaultarr = new byte[0];
        /// <summary>
        /// 返回读取数据,如果返回null则表示 读取出错,或者已经不能读取了,一次读取2KB数据
        /// </summary>
        /// <returns>返回读取到的数据</returns>
        /// <param name="bufferSize">设置读取字节大小</param>
        public byte[] Read(int bufferSize = 2048)
        {
            if (!CanWriteRead)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            byte[] temp = new byte[bufferSize];
            int len = 0;
            //lock (wrieStream)
            lock (readStream)
            {
                len = readStream.Read(temp, 0, temp.Length);
                //获取或者设置位置
                CurrentRead = readStream.BaseStream.Position;
            }
            //读取小于2K
            if (len != temp.Length)
            {
                if (len > 0)
                {
                    //return temp.Take(len).ToArray();

                    var temparr = new byte[len];
                    Buffer.BlockCopy(temp, 0, temparr, 0, len);
                    return temparr;

                }
                else
                {
                    return defaultarr;
                }
            }
            else
            {
                //读完2K直接返回
                return temp;
            }

            return null;
        }




        /// <summary>
        /// 是否可读写
        /// </summary>
        private bool canWriteRead = true;
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            if(CanWriteRead)
            {
                CanWriteRead = false;
                try
                {

                    wrieStream.Close();
                    readStream.Close();
                    readFileStrema.Close();
                    writeFileStrema.Close();
                }
                catch
                {
                }
                try
                {

                    wrieStream.Dispose();
                    readStream.Dispose();
                    readFileStrema.Dispose();
                    writeFileStrema.Dispose();
                }
                catch
                {
                }
            }

        }

        #endregion


    }
}
